from _sender import MsgSender
from config import OFFICIAL_APIS
from typing import Optional, List, Dict, Any, Union
from pathlib import Path
import base64
from hashlib import md5
from utils import is_image, is_file, is_video, is_voice


class ChatBotSender(MsgSender):
    """
    企业微信机器人，支持多种消息类型的发送

    Attributes:
        key: 机器人密钥
        log_level: 日志级别
        webhook_send_api: 消息发送API地址
        _media_api: 媒体文件上传API地址
    """

    key: str
    webhook_send_api: str

    def __init__(self, key: str = '', log_level: int = 20, *args, **kwargs):
        """
        初始化企业微信机器人

        Args:
            key: 机器人密钥，如果不提供则从配置文件读取
            log_level: 日志级别，默认20（INFO）
            **kwargs: 其他参数
        """
        super().__init__(log_level, *args, **kwargs)
        keyValue = self._get_corp_key(key=key).get('key', '')
        self.logger.info(f"key value is {keyValue}")
        self.key = keyValue
        self.headers = {'Content-Type': 'application/json; charset=utf-8'}
        webhook_send_api_value = self.base_url.format(
            OFFICIAL_APIS['WEBHOOK_SEND'].format(self.key))
        self.webhook_send_api = webhook_send_api_value
        self.logger.info(f"webhook_send_api value is {webhook_send_api_value}")
        self._media_api = self.base_url.format(
            OFFICIAL_APIS['WEBHOOK_MEDIA_UPLOAD'].format(self.key))

    def _get_corp_key(self, key: str = ''):
        """
        获取机器人密钥

        Args:
            key: 直接提供的密钥

        Returns:
            包含密钥的字典

        Raises:
            KeyConfigError: 当无法获取密钥时
        """
        if key:
            return {
                'key': key
            }
        return {
            'key': next(self._get_local_key(section='chatbot', options=['key']))
        }

    def _prepare_image_data(self, image_path: str) -> Dict[str, str]:
        """
        准备图片消息数据

        Args:
            image_path: 图片文件路径

        Returns:
            包含base64编码和MD5的图片数据字典
        """
        img_content = Path(image_path).open('rb').read()
        return {
            'base64': base64.b64encode(img_content).decode(),
            'md5': md5(img_content).hexdigest()
        }

    def _prepare_markdown_content(self, content: str) -> str:
        """
        准备markdown内容

        Args:
            content: markdown内容或文件路径

        Returns:
            处理后的markdown内容
        """
        if content.endswith('.md'):
            try:
                return Path(content).read_text()
            except (OSError, FileNotFoundError) as e:
                self.logger.warning(
                    '你可能正在尝试发送一个markdown文件，但文件并不存在或文件名过长，将直接发送内容.'
                )
        return content

    def _send(
        self,
        msg_type: str,
        data: Dict[str, Any],
        media_path: Optional[str] = '',
        **kwargs: Any
    ) -> Dict[str, Any]:
        """
        发送消息的统一方法

        Args:
            msg_type: 消息类型
            data: 消息数据
            media_path: 媒体文件路径
            **kwargs: 其他参数

        Returns:
            发送结果

        Raises:
            MessageError: 消息发送失败时
        """
        data['msgtype'] = msg_type

        if msg_type == 'image':
            data['image'] = self._prepare_image_data(media_path)
        elif msg_type == 'markdown':
            data['markdown']['content'] = self._prepare_markdown_content(
                data['markdown']['content']
            )
        elif msg_type == 'file':
            media_res = self._get_media_id(
                media_type='file',
                p_media=Path(media_path)
            )
            data[msg_type]['media_id'] = media_res.get('media_id', '')

        return self._post(self.webhook_send_api, data)

    def send_text(
        self,
        content: str,
        mentioned_list: List[str] = None,
        mentioned_mobile_list: List[str] = None
    ) -> Dict[str, Any]:
        """
        发送文本消息

        Args:
            content: 文本内容，最长不能超过2048字节，utf-8编码
            mentioned_list: userid列表，提醒群中某个成员，userid通过企业通讯录查看，'@all'则提醒所有人
            mentioned_mobile_list: 手机号列表，提醒手机号对应的成员，'@all'代表所有人

        Returns:
            发送结果

        Raises:
            MessageError: 消息内容为空时
        """
        if not content:
            self.logger.error(self.errmsgs['text_error'])
            return {
                'errcode': 404,
                'errmsg': self.errmsgs['text_error']
            }

        data = {
            "text": {
                "content": content,
                "mentioned_list": mentioned_list or [],
                "mentioned_mobile_list": mentioned_mobile_list or []
            }
        }
        return self._send(msg_type='text', data=data)

    def send_image(self, image_path: str) -> Dict[str, Any]:
        """
        发送图片消息

        Args:
            image_path: 图片文件路径，限制大小2M，支持JPG，PNG格式

        Returns:
            发送结果

        Raises:
            MessageError: 图片文件不合法时
        """
        if not is_image(image_path):
            self.logger.error(self.errmsgs['image_error'])
            return {
                'errcode': 404,
                'errmsg': self.errmsgs['image_error']
            }

        data = {
            "image": {
                "base64": '',
                "md5": '',
            }
        }
        return self._send(msg_type='image', data=data, media_path=image_path)

    def send_news(
        self,
        title: str,
        desp: str = '',
        url: str = '',
        picurl: str = ''
    ) -> Dict[str, Any]:
        """
        发送图文消息

        Args:
            title: 图文标题，不超过128个字节，超过会自动截断
            desp: 图文描述，可选，不超过512个字节，超过会自动截断
            url: 跳转链接
            picurl: 图片url，支持JPG、PNG格式，较好的效果为大图 1068*455，小图150*150

        Returns:
            发送结果

        Raises:
            MessageError: 标题或链接为空时
        """
        if not (title and url):
            self.logger.error(self.errmsgs['news_error'])
            return {
                'errcode': 404,
                'errmsg': self.errmsgs['news_error']
            }

        data = {
            "news": {
                "articles": [
                    {
                        "title": title,
                        "description": desp,
                        "url": url,
                        "picurl": picurl
                    }
                ]
            }
        }
        return self._send(msg_type='news', data=data)

    def send_markdown(self, content: str) -> Dict[str, Any]:
        """
        发送markdown消息

        Args:
            content: markdown内容或markdown文件路径

        Returns:
            发送结果

        Raises:
            MessageError: 内容为空时
        """
        if not content:
            self.logger.error(self.errmsgs['markdown_error'])
            return {
                'errcode': 404,
                'errmsg': self.errmsgs['markdown_error']
            }

        data = {
            "markdown": {
                "content": self._prepare_markdown_content(content)
            }
        }
        return self._send(msg_type='markdown', data=data)

    def send_file(self, file_path: str) -> Dict[str, Any]:
        """
        发送文件

        Args:
            file_path: 文件路径

        Returns:
            发送结果

        Raises:
            MessageError: 文件不合法时
        """
        if not is_file(file_path):
            self.logger.error(self.errmsgs['file_error'])
            return {
                'errcode': 404,
                'errmsg': self.errmsgs['file_error']
            }

        data = {
            "file": {
                "media_id": '',
            }
        }
        return self._send(msg_type='file', data=data, media_path=file_path)

